package com.qiangzi.workflow.engine.bpmn.task;

import java.util.concurrent.ConcurrentHashMap;

import org.dom4j.Attribute;
import org.dom4j.Element;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;

import com.qiangzi.workflow.engine.bpmn.base.ProcessInstance;
import com.qiangzi.workflow.engine.bpmn.delegate.DelegateExecution;
import com.qiangzi.workflow.engine.bpmn.delegate.ExecutionContext;
import com.qiangzi.workflow.engine.bpmn.delegate.JavaDelegate;

public class ServiceTask extends Task {

    // 整个JVM共用的部分
    //可能涉及到类的加载/卸载
    private static final ConcurrentHashMap<String, Object> CACHED_JAVA_DELEGATE = new ConcurrentHashMap<String, Object>();
    private static final Object                            LOCK                 = new Object();

    private String                                         className;

    public String getClassName() {
        return className;
    }

    @SuppressWarnings("rawtypes")
    public void parse(Element element) throws Exception {

        super.parse(element);

        Assert.isTrue(null != element, "element is null");

        // 提取class的值
        Attribute classAttribute = element.attribute("class");
        Assert.isTrue(null != classAttribute, "class attribute must exist in Task");
        String className = classAttribute.getText();
        Assert.hasText(className, "class attribute not valid in Task");
        // 确保是JavaDelegate类
        Class businessClass = Class.forName(className);
        Assert.isAssignable(JavaDelegate.class, businessClass,
            "wrong class,It must be implementation of interface JavaDelegate - " + className);
        this.className = className;

    }

    public Object copy() {
        ServiceTask serviceTask = new ServiceTask();
        copy(serviceTask);
        return serviceTask;
    }

    protected void copy(Object obj) {
        super.copy(obj);

        ServiceTask task = (ServiceTask) obj;
        task.className = this.className;

    }

    /**
     * 覆盖
     * 
     * @throws Exception
     */
    @Override
    public void invoke(ProcessInstance instance,
                       ApplicationContext applicationContext) throws Exception {

        // action部分
        Object cachedObject = CACHED_JAVA_DELEGATE.get(className);
        if (null == cachedObject) {
            synchronized (LOCK) {
                cachedObject = CACHED_JAVA_DELEGATE.get(className);
                if (null == cachedObject) {
                    cachedObject = applicationContext.getBean(Class.forName(className));
                    CACHED_JAVA_DELEGATE.put(className, cachedObject);
                }
            }
        }
        //从spring context中获取bean
        //因为可能涉及到类的加载/卸载
        //Object cachedObject = applicationContext.getBean(Class.forName(className));
        Assert.isTrue(null != cachedObject, "fail to get bean obj for " + className);
        Assert.isTrue(cachedObject instanceof JavaDelegate,
            "bean obj must be JavaDelegate type for " + className);
        JavaDelegate delegate = (JavaDelegate) cachedObject;
        DelegateExecution executionContext = new ExecutionContext(instance);
        delegate.execute(executionContext);

        // 这里直接调用node的invoke函数
        // 因为针对ServiceTask来说-其它都是类似的操作,没有特别的语义
        // 所以直接复用了父类的逻辑
        super.invoke(instance, applicationContext);

    }

}
